package com.iteaj.iot.test.modbus;

import com.fazecast.jSerialComm.SerialPort;
import com.iteaj.iot.client.ClientProtocolHandle;
import com.iteaj.iot.format.DataFormat;
import com.iteaj.iot.format.DataFormatConvert;
import com.iteaj.iot.modbus.Payload;
import com.iteaj.iot.modbus.WriteConvert;
import com.iteaj.iot.modbus.client.rtu.ModbusRtuClientComponent;
import com.iteaj.iot.modbus.client.rtu.ModbusRtuClientProtocol;
import com.iteaj.iot.modbus.client.tcp.ModbusTcpClientCommonProtocol;
import com.iteaj.iot.modbus.client.tcp.ModbusTcpClientComponent;
import com.iteaj.iot.modbus.consts.ModbusBitStatus;
import com.iteaj.iot.modbus.consts.ModbusCoilStatus;
import com.iteaj.iot.modbus.server.rtu.ModbusRtuHeader;
import com.iteaj.iot.modbus.server.tcp.ModbusTcpHeader;
import com.iteaj.iot.serial.SerialPortCreator;
import com.iteaj.iot.test.IotTestHandle;
import com.iteaj.iot.test.IotTestProperties;
import com.iteaj.iot.test.TestConst;
import com.iteaj.iot.utils.ByteUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;
import java.util.concurrent.TimeUnit;

public class ModbusTestHandle implements ClientProtocolHandle<ModbusTcpClientCommonProtocol>, IotTestHandle {

    @Autowired
    private IotTestProperties properties;
    @Autowired
    private ModbusTcpClientComponent modbusTcpClientComponent;
    @Autowired
    private ModbusRtuClientComponent modbusRtuClientComponent;

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    public Object handle(ModbusTcpClientCommonProtocol protocol) {
        return null;
    }

    @Override
    public void start() throws Exception {
        System.out.println("------------------ modbus客户端测试时使用的服务端模拟工具地址(https://gitee.com/qsaker/QtSwissArmyKnife) -------------");
        DataFormat format = DataFormat.DCBA;
        System.out.println("-------------------------------------- Modbus Tcp测试("+format+") ----------------------------------------------");
        //测试读写单个线圈
        ModbusCoilStatus write05 = ModbusCoilStatus.ON;
        ModbusTcpClientCommonProtocol.buildWrite05(1, 0, write05).request();
        ModbusTcpClientCommonProtocol.buildRead01(1, 0, 1).request(protocol -> {
            ModbusTcpClientCommonProtocol commonProtocol = (ModbusTcpClientCommonProtocol) protocol;
            ModbusBitStatus modbusBitStatus = commonProtocol.getPayload().readStatus(0);

            boolean status = (write05 == ModbusCoilStatus.ON && modbusBitStatus == ModbusBitStatus.ON)
                    || (write05 == ModbusCoilStatus.OFF && modbusBitStatus == ModbusBitStatus.OFF);

            ModbusTcpHeader head = commonProtocol.requestMessage().getHead();
            logger.info(TestConst.LOGGER_MODBUS_DESC, modbusTcpClientComponent.getName()
                    , "Write05 -> Read01", head.getEquipCode(), head.getMessageId(), 0
                    , status ? "通过" : "失败", write05);
            return null;
        });

        // 测试读写多个线圈
        byte[] write0f = new byte[] {(byte) 0xFF};
        ModbusTcpClientCommonProtocol.buildWrite0F(1, 3, write0f).request();
        ModbusTcpClientCommonProtocol.buildRead01(1, 3, 16).request(protocol -> {
            ModbusTcpClientCommonProtocol commonProtocol = (ModbusTcpClientCommonProtocol) protocol;
            Payload payload = commonProtocol.getPayload();
            ModbusTcpHeader head = commonProtocol.requestMessage().getHead();
            logger.info(TestConst.LOGGER_MODBUS_DESC, modbusTcpClientComponent.getName()
                    , "Write0F -> Read01", head.getEquipCode(), head.getMessageId(), 3
                    , write0f[0] == payload.getPayload()[0] ? "通过" : "失败", write0f[0]);
        });

        // 写单个寄存器测试
        short write06 = 72;
        ModbusTcpClientCommonProtocol.buildWrite06(1, 3, ByteUtil.getBytesOfReverse(write06)).request();
        ModbusTcpClientCommonProtocol.buildRead03(1, 3, 1).request(protocol -> {
            ModbusTcpClientCommonProtocol commonProtocol = (ModbusTcpClientCommonProtocol) protocol;
            ModbusTcpHeader head = commonProtocol.requestMessage().getHead();
            short i = commonProtocol.getPayload(format).readShort(3);
            logger.info(TestConst.LOGGER_MODBUS_DESC, modbusTcpClientComponent.getName()
                    , "Write06 -> Read03", head.getEquipCode(), head.getMessageId(), 3
                    , i == write06 ? "通过" : "失败", write06);
            return null;
        });

        ModbusTcpClientCommonProtocol.buildWrite06(1, 4, write06).request();
        ModbusTcpClientCommonProtocol.buildRead03(1, 4, 1).request(protocol -> {
            ModbusTcpClientCommonProtocol commonProtocol = (ModbusTcpClientCommonProtocol) protocol;
            ModbusTcpHeader head = commonProtocol.requestMessage().getHead();
            short i = commonProtocol.getPayload(format).readShort(4);
            logger.info(TestConst.LOGGER_MODBUS_DESC, modbusTcpClientComponent.getName()
                    , "Write06(arg) -> Read03", head.getEquipCode(), head.getMessageId(), 4
                    , i == write06 ? "通过" : "失败", write06);
            return null;
        });

        // 写多个寄存器测试
        int write10 = 10020030;
        ModbusTcpClientCommonProtocol.buildWrite10(1, 6, format, write10).request();
        ModbusTcpClientCommonProtocol.buildRead03(1, 6, 2).request(protocol -> {
            ModbusTcpClientCommonProtocol commonProtocol = (ModbusTcpClientCommonProtocol) protocol;
            ModbusTcpHeader head = commonProtocol.requestMessage().getHead();
            int i = commonProtocol.getPayload(format).readInt(6);
            logger.info(TestConst.LOGGER_MODBUS_DESC, modbusTcpClientComponent.getName()
                    , "Write10(args) -> Read03", head.getEquipCode(), head.getMessageId(), 6
                    , i == write10 ? "通过" : "失败", write10);
            return null;
        });

        ModbusTcpClientCommonProtocol.buildWrite10(1, 20, 2
                , DataFormatConvert.getInstance(format).getBytes(write10)).request();
        ModbusTcpClientCommonProtocol.buildRead03(1, 20, 2).request(protocol -> {
            ModbusTcpClientCommonProtocol commonProtocol = (ModbusTcpClientCommonProtocol) protocol;
            ModbusTcpHeader head = commonProtocol.requestMessage().getHead();
            int i = commonProtocol.getPayload(format).readInt(20);
            logger.info(TestConst.LOGGER_MODBUS_DESC, modbusTcpClientComponent.getName()
                    , "Write10(byte) -> Read03", head.getEquipCode(), head.getMessageId(), 20
                    , i == write10 ? "通过" : "失败", write10);
            return null;
        });

        ModbusTcpClientCommonProtocol.buildWrite10(1, 30, WriteConvert.build(write10, format)).request();
        ModbusTcpClientCommonProtocol.buildRead03(1, 30, 2).request(protocol -> {
            ModbusTcpClientCommonProtocol commonProtocol = (ModbusTcpClientCommonProtocol) protocol;
            ModbusTcpHeader head = commonProtocol.requestMessage().getHead();
            int i = commonProtocol.getPayload(format).readInt(30);
            logger.info(TestConst.LOGGER_MODBUS_DESC, modbusTcpClientComponent.getName()
                    , "Write10(convert) -> Read03", head.getEquipCode(), head.getMessageId(), 30
                    , i == write10 ? "通过" : "失败", write10);
            return null;
        });

        ModbusTcpClientCommonProtocol.buildWrite10(1, 660, format, (short)5, 2, 1.8f, 3.5, 300000L, "你好").request();
        ModbusTcpClientCommonProtocol.buildRead03(1, 660, 16).request(protocol -> {
            ModbusTcpClientCommonProtocol commonProtocol = (ModbusTcpClientCommonProtocol) protocol;
            Payload payload = commonProtocol.getPayload(format);
            short aShort = payload.readShort(660);
            int readInt = payload.readInt(661);
            float readFloat = payload.readFloat(663);
            double readDouble = payload.readDouble(665);
            long readLong = payload.readLong(669);
            String readString = payload.readString(673, 3);

            ModbusTcpHeader head = commonProtocol.requestMessage().getHead();
            logger.info(TestConst.LOGGER_MODBUS_DESC, modbusTcpClientComponent.getName(), "Write10(args) -> Read03", head.getEquipCode(), head.getMessageId(), 660
                    , 5==aShort && 2==readInt && 1.8f==readFloat && 3.5==readDouble && 300000L == readLong && "你好".equals(readString) ? "通过" : "失败", "5, 2, 1.8f, 3.5, 300000L, 你好");

            return null;
        });

        List<SerialPort> available = SerialPortCreator.available();
        if(properties.isSerialStart() && available.size() >= 4) {
            System.out.println("-------------------------------------- Modbus Rtu测试("+format+") ----------------------------------------------");
            String com = available.get(2).getSystemPortName();
            ModbusRtuClientProtocol.buildWrite05(1, 0, write05).request(com);
            ModbusRtuClientProtocol.buildRead01(1, 0, 1).request(com, protocol -> {
                ModbusBitStatus modbusBitStatus = protocol.getPayload().readStatus(0);

                boolean status = (write05 == ModbusCoilStatus.ON && modbusBitStatus == ModbusBitStatus.ON)
                        || (write05 == ModbusCoilStatus.OFF && modbusBitStatus == ModbusBitStatus.OFF);

                ModbusRtuHeader head = protocol.requestMessage().getHead();
                logger.info(TestConst.LOGGER_MODBUS_DESC, modbusRtuClientComponent.getName()
                        , "Write05 -> Read01", head.getEquipCode(), head.getMessageId(), 0
                        , status ? "通过" : "失败", write05);
            });

            ModbusRtuClientProtocol.buildWrite0F(1, 3, write0f).request(com);
            ModbusRtuClientProtocol.buildRead01(1, 3, 16).request(com, protocol -> {
                Payload payload = protocol.getPayload();
                ModbusRtuHeader head = protocol.requestMessage().getHead();
                logger.info(TestConst.LOGGER_MODBUS_DESC, modbusRtuClientComponent.getName()
                        , "Write0F -> Read01", head.getEquipCode(), head.getMessageId(), 3
                        , write0f[0] == payload.getPayload()[0] ? "通过" : "失败", write0f);
            });

            // 写单个寄存器测试
            ModbusRtuClientProtocol.buildWrite06(1, 3, ByteUtil.getBytesOfReverse(write06)).request(com);
            ModbusRtuClientProtocol.buildRead03(1, 3, 1).request(com, protocol -> {
                ModbusRtuHeader head = protocol.requestMessage().getHead();
                short i = protocol.getPayload(format).readShort(3);
                logger.info(TestConst.LOGGER_MODBUS_DESC, modbusRtuClientComponent.getName()
                        , "Write06 -> Read03", head.getEquipCode(), head.getMessageId(), 3
                        , i == write06 ? "通过" : "失败", write06);
            });

            ModbusRtuClientProtocol.buildWrite06(1, 4, write06).request(com);
            ModbusRtuClientProtocol.buildRead03(1, 4, 1).request(com, protocol -> {
                ModbusRtuHeader head = protocol.requestMessage().getHead();
                short i = protocol.getPayload(format).readShort(4);
                logger.info(TestConst.LOGGER_MODBUS_DESC, modbusRtuClientComponent.getName()
                        , "Write06(arg) -> Read03", head.getEquipCode(), head.getMessageId(), 4
                        , i == write06 ? "通过" : "失败", write06);
            });

            // 写多个寄存器测试
            ModbusRtuClientProtocol.buildWrite10(1, 6, format, write10).request(com);
            ModbusRtuClientProtocol.buildRead03(1, 6, 2).request(com, protocol -> {
                ModbusRtuHeader head = protocol.requestMessage().getHead();
                int i = protocol.getPayload(format).readInt(6);
                logger.info(TestConst.LOGGER_MODBUS_DESC, modbusRtuClientComponent.getName()
                        , "Write10(args) -> Read03", head.getEquipCode(), head.getMessageId(), 6
                        , i == write10 ? "通过" : "失败", write10);
            });

            ModbusRtuClientProtocol.buildWrite10(1, 20, 2, DataFormatConvert.getInstance(format).getBytes(write10)).request(com);
            ModbusRtuClientProtocol.buildRead03(1, 20, 2).request(com, protocol -> {
                ModbusRtuHeader head = protocol.requestMessage().getHead();
                int i = protocol.getPayload(format).readInt(20);
                logger.info(TestConst.LOGGER_MODBUS_DESC, modbusRtuClientComponent.getName()
                        , "Write10(byte) -> Read03", head.getEquipCode(), head.getMessageId(), 20
                        , i == write10 ? "通过" : "失败", write10);
            });

            ModbusRtuClientProtocol.buildWrite10(1, 30, WriteConvert.build(write10, format)).request(com);
            ModbusRtuClientProtocol.buildRead03(1, 30, 2).request(com, protocol -> {
                ModbusRtuHeader head = protocol.requestMessage().getHead();
                int i = protocol.getPayload(format).readInt(30);
                logger.info(TestConst.LOGGER_MODBUS_DESC, modbusRtuClientComponent.getName()
                        , "Write10(convert) -> Read03", head.getEquipCode(), head.getMessageId(), 30
                        , i == write10 ? "通过" : "失败", write10);
            });

            ModbusRtuClientProtocol.buildWrite10(1, 660, format, (short)5, 2, 1.8f, 3.5, 300000L, "你好").request(com);
            ModbusRtuClientProtocol.buildRead03(1, 660, 16).request(com, protocol -> {
                Payload payload = protocol.getPayload(format);
                short aShort = payload.readShort(660);
                int readInt = payload.readInt(661);
                float readFloat = payload.readFloat(663);
                double readDouble = payload.readDouble(665);
                long readLong = payload.readLong(669);
                String readString = payload.readString(673, 3);

                ModbusRtuHeader head = protocol.requestMessage().getHead();
                logger.info(TestConst.LOGGER_MODBUS_DESC, modbusRtuClientComponent.getName(), "Write10(args) -> Read03", head.getEquipCode(), head.getMessageId(), 660
                        , 5==aShort && 2==readInt && 1.8f==readFloat && 3.5==readDouble && 300000L == readLong && "你好".equals(readString) ? "通过" : "失败", "5, 2, 1.8f, 3.5, 300000L, 你好");

            });
        } else {
            System.out.println("------------------ 没有发现可用的串口 忽略modbus rtu测试 -------------");
        }

        TimeUnit.SECONDS.sleep(3);
    }

    @Override
    public int getOrder() {
        return 1000;
    }
}
